/*
 * Copyright (C) 2021 The Chinese Software International Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.qiujuer.genius.ui.widget;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.StackLayout;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import net.qiujuer.genius.ui.drawable.BalloonMarkerDrawable;

public class BalloonMarker extends ComponentContainer implements BalloonMarkerDrawable.MarkerAnimationListener,
    Component.EstimateSizeListener, Component.DrawTask, ComponentContainer.ArrangeListener, Component.BindStateChangedListener {
    private static final int ELEVATION_DP = 8;
    private static final int SEPARATION_DP = 0;
    //The drawable need new before this init method
    BalloonMarkerDrawable mBalloonMarkerDrawable = new BalloonMarkerDrawable(Color.TRANSPARENT.getValue(), 0);
    //The TextView to show the info
    private Text mNumber;
    //The max width of this View
    private int mWidth;
    //some distance between the thumb and our bubble marker.
    //This will be added to our measured height
    private int mSeparation;

    public BalloonMarker(Context context) {
        this(context, null);
        addDrawTask(this);
        setBindStateChangedListener(this);
    }

    public BalloonMarker(Context context, AttrSet attrs) {
        this(context, attrs, 0);
        addDrawTask(this);
        setBindStateChangedListener(this);
    }

    public BalloonMarker(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, String.valueOf(defStyleAttr));
        init(context, attrs, defStyleAttr, 0, "0");
        addDrawTask(this);
        setBindStateChangedListener(this);
    }

    public BalloonMarker(Context context, AttrSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, String.valueOf(defStyleAttr));
        init(context, attrs, defStyleAttr, defStyleRes, "0");
        addDrawTask(this);
        setBindStateChangedListener(this);
    }

//    @Override
//    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
//        super.onInitializeAccessibilityEvent(event);
//        event.setClassName(BalloonMarker.class.getName());
//    }
//
//    @Override
//    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
//        super.onInitializeAccessibilityNodeInfo(info);
//        info.setClassName(BalloonMarker.class.getName());
//    }


    public void init(Context context, AttrSet attrs, int defStyleAttr, int defStyleRes, String maxValue) {
        final float density = 1f;
        mNumber = new Text(context);
        mNumber.setTextAlignment(TextAlignment.CENTER);
        mNumber.setText(maxValue);
        mNumber.setMaxTextLines(1);
        mNumber.setMultipleLine(false);

        //UiCompat.setTextDirection(mNumber, 5); //5 is TEXT_DIRECTION_LOCALE
        mNumber.setVisibility(Component.INVISIBLE);

        // reset text size
        resetSizes(maxValue);

        mSeparation = (int) (SEPARATION_DP * density);

        mBalloonMarkerDrawable = new BalloonMarkerDrawable(Color.TRANSPARENT.getValue(), 0);
        mBalloonMarkerDrawable.setCallback(new Element.OnChangeListener() {
            @Override
            public void onChange(Element element) {

            }
        });
        mBalloonMarkerDrawable.setMarkerListener(this);
        mBalloonMarkerDrawable.setExternalOffset(getPaddingBottom());

        //UiCompat.setOutlineProvider(this, mBalloonMarkerDrawable);

        if (attrs != null) {
            int textPadding = TypedAttrUtils.getDimensionPixelSize(attrs, "gMarkerTextPadding", 2);
            int textAppearanceId = TypedAttrUtils.getDimensionPixelSize(attrs, "gMarkerTextAppearance", 0);
            int color = TypedAttrUtils.getDimensionPixelSize(attrs, "gMarkerBackgroundColor", 0);
            mSeparation = TypedAttrUtils.getDimensionPixelSize(attrs, "gMarkerSeparation", 16);
//            String fontFile= TypedAttrUtils.getString(attrs,"gFont","");
            setTextPadding(textPadding);
            setTextAppearance(textAppearanceId);
            setBackgroundColor(color);

           /* if (!this.isInEditMode()) {
                // Font
                if (fontFile != null && fontFile.length() > 0) {
                    Typeface typeface = Ui.getFont(getContext(), fontFile);
                    if (typeface != null) setTypeface(typeface);
                }
            }*/
        }

    }

    public void setSeparation(int separation) {
        this.mSeparation = separation;
    }

    public void setTextPadding(int padding) {
        mNumber.setPadding(padding, 0, padding, 0);
    }

//    public void setTypeface(Typeface typeface) {
//        mNumber.setTypeface(typeface);
//    }

    public void setTextAppearance(int resId) {
        //  mNumber.setTextAppearance(getContext(), resId);

    }

    public StateElement getBackgroundColor() {
        return mBalloonMarkerDrawable.getColorStateList();
    }

    public void setBackgroundColor(int color) {
        mBalloonMarkerDrawable.setColorStateList(color);
    }

    public void setClosedSize(float closedSize) {
        mBalloonMarkerDrawable.setClosedStateSize(closedSize);
    }

    public void resetSizes(String maxValue) {
        //   DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        //Account for negative numbers... is there any proper way of getting the biggest string between our range????
        mNumber.setText(String.format("-%s", maxValue));
        //Do a first forced measure call for the TextView (with the biggest text content),
        //to calculate the max width and use always the same.
        //this avoids the TextView from shrinking and growing when the text content changes
//        int wSpec = MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, MeasureSpec.AT_MOST);
//        int hSpec = MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, MeasureSpec.AT_MOST);
//        mNumber.measure(wSpec, hSpec);
        Paint paint = new Paint();
        paint.setTextSize(mNumber.getTextSize());
        float childWidth = paint.measureText(mNumber.getText());
        mWidth = (int) Math.max(childWidth, mNumber.getHeight());
        //removeView(mNumber);
        removeComponent(mNumber);
        addComponent(mNumber, new StackLayout.LayoutConfig(mWidth, mWidth, LayoutAlignment.LEFT | LayoutAlignment.TOP));
    }

    @Override
    public void setPadding(int left, int top, int right, int bottom) {
        super.setPadding(left, top, right, bottom);
        if (mBalloonMarkerDrawable != null) {
            mBalloonMarkerDrawable.setExternalOffset(bottom);
        }
    }

    /*    @Override
        protected void dispatchDraw(Canvas canvas) {

            super.dispatchDraw(canvas);
        }*/
    @Override
    public void onDraw(Component component, Canvas canvas) {
        mBalloonMarkerDrawable.draw(canvas, null);
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        //  measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthSize = mWidth + getPaddingLeft() + getPaddingRight();
        int heightSize = mWidth + getPaddingTop() + getPaddingBottom();
        //This diff is the basic calculation of the difference between
        //a square side size and its diagonal
        //this helps us account for the visual offset created by MarkerDrawable
        //when leaving one of the corners un-rounded
        int diff = (int) ((1.41f * mWidth) - mWidth) / 2;
        //setMeasuredDimension(widthSize, heightSize + diff + mSeparation);
        setEstimatedSize(widthSize, heightSize + diff + mSeparation);
        return false;
    }
/*    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthSize = mWidth + getPaddingLeft() + getPaddingRight();
        int heightSize = mWidth + getPaddingTop() + getPaddingBottom();
        //This diff is the basic calculation of the difference between
        //a square side size and its diagonal
        //this helps us account for the visual offset created by MarkerDrawable
        //when leaving one of the corners un-rounded
        int diff = (int) ((1.41f * mWidth) - mWidth) / 2;
        setMeasuredDimension(widthSize, heightSize + diff + mSeparation);
    }*/


    @Override
    public boolean onArrange(int i, int i1, int i2, int i3) {
        int left = getPaddingLeft();
        int top = getPaddingTop();
        int right = getWidth() - getPaddingRight();
        int bottom = getHeight() - getPaddingBottom();
        //the TetView is always layout at the top
        mNumber.arrange(left, top, left + mWidth, top + mWidth);
        //the MarkerDrawable uses the whole view, it will adapt itself...
        // or it seems so...
        mBalloonMarkerDrawable.setBounds(left, top, right, bottom);
        return false;
    }


    public CharSequence getValue() {
        return mNumber.getText();
    }

    public void setValue(CharSequence value) {
        mNumber.setText((String) value);
    }

    public void animateOpen() {
        mBalloonMarkerDrawable.stop();
        mBalloonMarkerDrawable.animateToPressed();
    }

    public void animateClose() {
        mBalloonMarkerDrawable.stop();
        AnimatorProperty animator = mNumber.createAnimatorProperty();
        animator.alpha(0f);
        animator.setDuration(100);
        animator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                mNumber.setVisibility(Component.INVISIBLE);
                mBalloonMarkerDrawable.animateToNormal();
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        }).start();
    }

    @Override
    public void onOpeningComplete() {
        mNumber.setVisibility(Component.VISIBLE);

        AnimatorProperty animator = mNumber.createAnimatorProperty();
        animator.alpha(1f);
        animator.setDuration(100);
        animator.start();

        if (getComponentParent() instanceof BalloonMarkerDrawable.MarkerAnimationListener) {
            ((BalloonMarkerDrawable.MarkerAnimationListener) getComponentParent()).onOpeningComplete();
        }
    }

    @Override
    public void onClosingComplete() {
        if (getComponentParent() instanceof BalloonMarkerDrawable.MarkerAnimationListener) {
            ((BalloonMarkerDrawable.MarkerAnimationListener) getComponentParent()).onClosingComplete();
        }
    }


    public void setColors(int startColor, int endColor) {
        mBalloonMarkerDrawable.setColors(startColor, endColor);
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        animateOpen();
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        mBalloonMarkerDrawable.stop();
    }
}
